#ifndef __CZF_SYNTAX_LIGHTER_H__
#define __CZF_SYNTAX_LIGHTER_H__

#include "TextDoc.h"
#include "HiliteConfig.h"
#include "vararryt.h"
#include "windows.h"

typedef struct tagCharPos {
    unsigned int row;
    unsigned int idx;
} CharPos;

// Block is used for storing comments and strings
#define UNSPEC_BLOCK    0
#define COMMENT_BLOCK   1
#define STRING_BLOCK    2

typedef struct tagBlock {
    unsigned int row1;
    unsigned int idx1;
    unsigned int row2;
    unsigned int idx2;
    unsigned int type;
    char         quote;
} Block;

/* Return the index of the result. If no match, returns the closet bigger one.
 *  in case, charpos is bigger than the last of the array, return count.
 */
unsigned int SearchCharPosInBlockArray (const Block* array, unsigned int count, const CharPos* pos, bool* inblock); 

/* Return -1, if charpos is at the "left" of the block, 
 * Return 0, if charpos is in the block.
 * Return 1, if charpos is at the "right" of the block.
 */
int CompareCharPosWithBlock(const CharPos* charpos, const Block* blk);

typedef CVarArrayT<Block> CBlockVector;

#define BLOCK_INIT 20
#define BLOCK_GROW 20
#define NORMAL                  0
#define IN_BLOCK_COMMENT        1
#define IN_STRING               2

typedef struct tagSyntaxColors {
    COLORREF normal;
    COLORREF keyword;
    COLORREF string;
    COLORREF comment;
} SyntaxColors;

#define DEFAULT_NORMALCOLOR     RGB(0, 0, 0)
#define DEFAULT_STRINGCOLOR     RGB(140, 140, 140)
#define DEFAULT_COMMENTCOLOR    RGB(0, 140, 0)
#define DEFAULT_KEYWORDCOLOR    RGB(0, 0, 255)

class CSyntaxLighter
{
public:
    CSyntaxLighter();
    virtual ~CSyntaxLighter();
    
    void SetDocument (const CTextDoc* doc);
    void SetSyntax (const CSyntaxConfig* syntax);
    Block* GetBlocks();
    int FindAllBlocks();
    // ColorTheLine, allocates memory for color, returns the length of the array.
    // *color should be freed by caller.
    int ColorTheLine(unsigned int line, const char* txt, COLORREF** color);
    bool IsIndent(const char* str);
    bool IsUnindent(const char* str);

public:
    unsigned int        m_nBlocks;
    SyntaxColors        m_colors;

protected:
    CTextDoc*           m_doc;
    CSyntaxConfig*      m_syntax;
    CBlockVector        m_vecBlocks;

protected:
    void ClearBlocks();
    int AddBlock(const Block* blk);
    unsigned int FindNextBlockStart(CharPos* pos, Block* blk);
    const char* FindQuote(const char* str, char quote='\0');
    unsigned int FindNextBlockCommentOff(CharPos* pos, Block* blk);
    unsigned int MatchQuote(CharPos* pos, Block* blk);
// helpers
    void SetBlockEndPosition (Block* blk, const char* txt, CharPos* pos);
    unsigned int AddToBlockVector (const Block* blk);
    // pos is updated to the start of nextblk.
    // if nextblk == NULL, color to the end.
    void ColorUntilNextBlock (COLORREF* colorarray, size_t size, const Block* nextblk, CharPos* pos, const char* txt);
    void ColorThisBlock(COLORREF* colorarray, size_t size, const Block* blk, CharPos* pos);
    void ColorWord(COLORREF* colorarray, const char* txt, unsigned int start, unsigned int end);
};

#endif /* __CZF_SYNTAX_LIGHTER_H__*/

